using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;

namespace kerberosLibs
{
	/// <summary>
	/// Summary description for ConnectionTask.
	/// </summary>
	public abstract class ConnectionTask : System.ComponentModel.Component
	{
		/// <summary>
		/// Required designer variable.
		/// </summary>
		private System.ComponentModel.Container components = null;

		public ConnectionTask(System.ComponentModel.IContainer container)
		{
			///
			/// Required for Windows.Forms Class Composition Designer support
			///
			container.Add(this);
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		public ConnectionTask()
		{
			///
			/// Required for Windows.Forms Class Composition Designer support
			///
			InitializeComponent();

			//
			// TODO: Add any constructor code after InitializeComponent call
			//
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		/// <summary>
		/// How many steps does this guy go through to do its job (for UI updating). If you change this
		/// be sure to raise the event OnLastStepChanged!
		/// </summary>
		public abstract int NumberOfSteps 
		{
			get;
		}

		/// <summary>
		/// Name of task. Used for user interaction.
		/// </summary>
		public string TaskName 
		{
			get {return _taskName;}
			set {_taskName = value;}
		}
		private string _taskName;

		/// <summary>
		/// We report this as the first absolute step number. So several jobs can be linked together.
		/// </summary>
		public int FirstStepNumber 
		{
			get {return _firstStepNumber;}
			set {
				_firstStepNumber = value;
				OnLastTaskNumberChanged();
			}
		}

		/// <summary>
		/// Returns the last number this guy will send back.
		/// </summary>
		public int LastTaskNumber
		{
			get {return _firstStepNumber + NumberOfSteps - 1;}
		}

		public delegate void LastTaskNumberChangedDelegate (int lastTaskNumber);

		/// <summary>
		/// Raised when the task numbering changes.
		/// </summary>
		public event LastTaskNumberChangedDelegate LastTaskNumberChanged;

		/// <summary>
		/// Call when the last task number changes! This is so people downstream can update their #s.
		/// </summary>
		protected virtual void OnLastTaskNumberChanged ()
		{
			if (LastTaskNumberChanged != null) 
			{
				LastTaskNumberChanged (LastTaskNumber);
			}
		}

		/// <summary>
		/// What is the first step number we will take?
		/// </summary>
		private int _firstStepNumber = 0;

		/// <summary>
		/// Delagate gets called each time somethign has progressed. Step number and any nice easy
		/// user text message are displayed. The absolute_step_number is the interanl step number plus
		/// the "FirstStepNumber" property!
		/// </summary>
		public delegate void UIStatusUpdate (int absolute_step_number, string message);

		/// <summary>
		/// Subscribe to know when updates occur in this task.
		/// </summary>
		public event UIStatusUpdate StatusUpdate;

		/// <summary>
		/// Raises the StatusUpdate event. Override if you want ot capture. Note called with
		/// an internal step number, but needs to send out an absolute one! Internal step numbers
		/// should start with zero!
		/// </summary>
		/// <param name="internal_step_number"></param>
		/// <param name="message"></param>
		public virtual void OnUIStatusUpdate (int internal_step_number, string message) 
		{
			if (StatusUpdate != null) 
			{
				StatusUpdate (internal_step_number + FirstStepNumber, message);
			}
		}

		/// <summary>
		/// Delegate that gets called when a task is done.
		/// </summary>
		public delegate void TaskDone ();

		public event TaskDone Done;

		/// <summary>
		/// Raise the Done event. When the task is finished...
		/// </summary>
		public virtual void OnTaskDone ()
		{
			if (Done != null) 
			{
				Done();
			}
		}

		/// <summary>
		/// Start the task running.
		/// </summary>
		public abstract void Start();

		/// <summary>
		/// We start when this task has finished. We will hook up and configure task numbering, and subscribe
		/// to their Done event.
		/// </summary>
		public ConnectionTask PreviousTask 
		{
			get {return _previousTask;}
			set 
			{
				///
				/// Protect against idiots (like me).
				///

				if (value == this) 
				{
					throw new System.ArgumentException ("A Task can't the the Previous Task of itself!");
				}

				///
				/// If we have an old previous task, get rid of it
				/// 

				if (_previousTask != null) 
				{
					_previousTask.Done -= new TaskDone(this.Start);
					_previousTask.LastTaskNumberChanged -= new LastTaskNumberChangedDelegate(_previousTask_LastTaskNumberChanged);
					_firstStepNumber = 0;
				}

				///
				/// Link up with the new task.
				///

				_previousTask = value;
				if (_previousTask != null) 
				{
					_previousTask.Done += new TaskDone(this.Start);
					_previousTask.LastTaskNumberChanged += new LastTaskNumberChangedDelegate(_previousTask_LastTaskNumberChanged);
					_previousTask_LastTaskNumberChanged(_previousTask.LastTaskNumber);
				}
			}
		}

		private ConnectionTask _previousTask = null;

		#region Component Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			components = new System.ComponentModel.Container();
		}
		#endregion

		/// <summary>
		/// We need to update our numbering, and propagate the change on down!
		/// </summary>
		/// <param name="lastTaskNumber"></param>
		private void _previousTask_LastTaskNumberChanged(int lastTaskNumber)
		{
			FirstStepNumber = _previousTask.LastTaskNumber + 1;
		}
	}
}
